<?php
class Model_Mapper_Generic extends Atualtec_Db_Mapper
{
	private $_table;
	
	private $_nameModel;
	
	private $_nameMapper;
	
	private $_nameDbTable;
	
	public function __construct($table)
	{
		$this->_table = $table;
		
		$name = explode('_', str_replace('tb_', '', $table));
		foreach($name as $key => $part) {
			$name[$key] = ucfirst($part);
		}
		
		$this->_nameModel = 'Model_'.implode('', $name);
		$this->_nameMapper = 'Model_Mapper_'.implode('', $name);
		$this->_nameDbTable = 'Model_DbTable_'.implode('', $name);
		
		$this->setDbTable($this->_nameDbTable);
		return $this;
	}
	
	public function getNameDbTable()
	{ }
	
	public function getListTableData($filters, $pageNumber)
	{
		$paginator = $this->_getDbSelect($filters);
		
		// Columns of table
		$tableCols = $paginator->getIterator()->getTable()->info('cols');
		
		// Clone object
		$items = clone $paginator;
		
		// Variables
		$fields = array();
		$values = array();
		$nmExists = false;
		
		// It's a greeeeat loop, but it make necessary...
		foreach($items as $key => $row)
		{
			$methods = get_class_methods($row);
			
			foreach($methods as $method)
			{
				// Columns names
				$manyToMany = (bool) preg_match('/_nm_/i', $method);
				$name = preg_replace(
					array('/get/', '/fk_/i', '/_nm_/i', '/_/'),
					array('', '', ' ', ' '),
					$method
				);
				$name = ucwords(strtolower($name));
				$name .= ($manyToMany) ? 's' : '';
				
				// First position
				if(preg_match('/^getPk_/', $method)) {
					if(!in_array('ID', $fields)) {
						$fields[] = 'ID';
					}
					$values[$key][] = $row->$method();
					
				// Foreign values
				} elseif(preg_match('/^getFk/', $method)) {
					if(!in_array($name, $fields)) {
						$fields[] = $name;
					}
					$fk = $row->$method();
					
					if(is_object($fk)) {
						$fkMethods = get_class_methods($fk);
						foreach($fkMethods as $fkMethod) {
							if(preg_match('/^getName/', $fkMethod)) {
								$values[$key][] = $fk->$fkMethod();
								break;
							}
						}
					} else {
						$values[$key][] = empty($fk) ? '--' : $fk;
					}
				// Many to many values
				} elseif(preg_match('/^get.+_nm_/', $method)) {
					
					$nmExists = true;
					
					if(!in_array($name, $fields)) {
						$fields[] = $name;
					}
					$nmObject = $row->$method();
					
					foreach($nmObject as $nmRow) {
						$nmMethods = get_class_methods($nmRow);
						foreach($nmMethods as $nmMethod) {
							if(preg_match('/^getName/', $nmMethod)) {
								$values[$key]['nm'][] = $nmRow->$nmMethod();
								break;
								break;
							}
						}
					}
					
					// Add mn field to the columns
					$nmCol = strtolower(preg_replace('/^get/', '', $method));
					if(!in_array($nmCol, $tableCols)) {
						$tableCols[] = $nmCol;
					}
					
				// Every values else
				} elseif(preg_match('/^get/', $method)) {
					if(!in_array($name, $fields)) {
						$fields[] = $name;
					}
					$values[$key][] = $row->$method();
				}
			}
			
			if(!isset($values[$key]['nm']) && $nmExists) {
				$values[$key]['nm'] = array();
			}
		}
		
		return array(
			'paginator' => $paginator,
			'data' => array(
				'fields' => $fields,
				'values' => $values,
				'columns' => $tableCols
			)
		);
	}
	
	private function _getJoinReference($tableDbTable)
	{
		$reference = $tableDbTable->getReference($this->_nameDbTable);

		$refString = '(';
		$refString .= $tableDbTable->getTableName();
		$refString .= '.';
		$refString .= $reference['columns'][0];
		$refString .= ' = ';
		$refString .= $this->getDbTable()->getTableName();
		$refString .= '.';
		$refString .= $reference['refColumns'][0];
		$refString .= ')';
		
		return $refString;
	}
	
	private function _getDbSelect($filters = null)
	{
		$sql = $this->getDbTable()
			->setRowClass($this->_nameModel)
			->select()
			->setIntegrityCheck(false)
			->from($this->_table, array('*'), 'cms');
		
		$tablesMetadata[] = $this->getDbTable()->info('metadata');
		
		// Related tables
		foreach($this->getDbTable()->getDependentTables() as $table)
		{
			$tableDbTable = new $table();
			
			$tablesMetadata[] = $tableDbTable->info('metadata');
			
			$sql->join(
				$tableDbTable->getName(),
				$this->_getJoinReference($tableDbTable),
				array('*'),
				'cms'
			);
		}
		
		// Filters
		if(!empty($filters)) {
			foreach($this->_getWheres($filters, $tablesMetadata) as $clause) {
				$sql->where($clause['where'], $clause['filter'], $clause['type']);
			}
		}
		
		$pageNumber = Zend_Controller_Front::getInstance()
			->getRequest()
			->getParam('pagina');
		
		return Zend_Paginator::factory($sql)
			->setCurrentPageNumber($pageNumber)
			->setItemCountPerPage(2)
			->setPageRange(10);
	}
	
	public function _getWheres($filters, $metadata)
	{
		$wheres = array();
		
		foreach($filters as $columnName => $filter) {
			if(!empty($filter)) {
				foreach($metadata as $columns)
				{
					// Foreign keys
					if(preg_match('/fk_/i', $columnName) && !is_numeric($filter))
					{
						// If is a Foreign key
						$columnName = str_replace('fk_', 'name_', $columnName);
						
						$tbName = current($columns);
						$tbName = str_replace('tb_', '_', $tbName['TABLE_NAME']);
						
						$columnName = str_replace($tbName, '', $columnName);
					}
					
					// Many to many data
					if(preg_match('/_nm_/', $columnName)) {
						
					}
					
					if(array_key_exists($columnName, $columns))
					{
						$column = $columns[$columnName];
						
						$where = $column['SCHEMA_NAME'].'.';
						$where .= $column['TABLE_NAME'].'.';
						$where .= $column['COLUMN_NAME'];

						// If is a LIKE search
						if(preg_match('/char/i', $column['DATA_TYPE'])) {
							$where .= ' ILIKE ?';
							$filter = "%$filter%";
							$type = 'string';
						} elseif(preg_match('/int/i', $column['DATA_TYPE'])) {
							$where .= ' = ?';
							$type = 'integer';
						}

						$wheres[] = array(
							'where' => $where,
							'filter' => $filter,
							'type' => $type
						);
					}
				}
			}
		}
		return $wheres;
	}
	
	/**
	 *	Return array with years, months, days, hours, minutes and seconds elapsed
	 *  throuth two passed dates in timestamp
	 *	
	 * @param integer $begin Timestamp
	 * @param integer $end Timestamp
	 * @return array
	 */
	function timeleft($begin,$end)
	{
		$dif = $end-$begin;

		$years = intval($dif/(60*60*24*365));
		$dif = $dif-($years*(60*60*24*365));
		
		$months = intval($dif/(60*60*24*30));
		$dif = $dif-($months*(60*60*24*30));
		
		$weeks = intval($dif/(60*60*24*7));
		$dif = $dif-($weeks*(60*60*24*7));
		
		$days = intval($dif/(60*60*24));
		$dif = $dif-($days*(60*60*24));
		
		$hours = intval($dif/(60*60));
		$dif = $dif-($hours*(60*60));
		
		$minutes = intval($dif/(60));
		$seconds = $dif-($minutes*60);
		
		return array(
			'years' => $years*-1,
			'months' => $months*-1,
			'weeks' => $weeks*-1,
			'days' => $days*-1,
			'hours' => $hours*-1,
			'minutes' => $minutes*-1,
			'seconds' => $seconds*-1,
		);
	}
}